/**
 * 渲染引擎
 */
function sPainter(canvas) {
    this.ctx = canvas.getContext("2d");
    this.ctx.textBaseline = "alphabetic";

    const FONT_ASCENT = "fontBoundingBoxAscent";
    const FONT_DESCENT = "fontBoundingBoxDescent";

    /**
     * 文本缩放比
     */
    var scale = 1;

    /**
     * 分页对象
     */
    var page = null;

    /**
     * 设置图层对象
     */
    var plm = null;

    /**
     * 设置全局配置对象
     */
    var setting = null;

    /**
     * 偏移量工具
     */
    var ost = new sOffsetUtil();

    /**
     * 转换工具
     */
    var converter = new sConverter();

    /**
     * 获取画布大小
     */
    this.getSize = function(){
        return {
            width: canvas.width,
            height: canvas.height
        };
    }

    /**
     * 设置样式
     * @param {*} style 
     */
    this.setStyle = function(style){
        for(var i in style){
            this.ctx[i] = style[i];
        }
    }

    /**
     * 获取样式
     * @param {*} name 
     */
    this.getStyle = function(name){
        return this.ctx[name];
    }

    /**
     * 设置文本缩放比
     * @param {*} ratio 
     */
    this.setScale = function(ratio){
        scale = ratio;
    }

    /**
     * 设置分页信息
     * @param {*} spage 分页对象
     */
    this.setPage = function(spage){
        page = spage;
    }

    /**
     * 设置图层对象
     * @param {*} paintLayer 
     */
    this.setPaintLayer = function(paintLayer){
        plm = paintLayer;
    }

    /**
     * 设置全局配置对象
     * @param {*} globalSetting 
     */
    this.setSetting = function(globalSetting){
        setting = globalSetting;
    }

    /**
     * 创建一个新实例
     */
    this.createPainter = function(){
        return new sPainter(canvas);
    }

    /**
     * 绘制布局
     * @param {*} page 分页对象
     * @param {*} opt 可选参数
     */
    this.drawLayout = function (page, opt) {
        if (opt && !opt.head && !opt.foot) return;

        plm.createLayer(
            "pageBackground",
            ssDict.sPaintLayerLevel.PAGE_BACKGROUND,
            page.getIndex()
        ).push({
            name: "pageBackground",
            arguments: [opt],
            method: (opt)=>{
                var len = 42;

                this.ctx.lineWidth = 1.5;
                this.ctx.strokeStyle = "#aaa";

                var pageRect = page.getBoundRect();

                //页眉部分
                var boundRect = page.getPadding();

                this.ctx.beginPath();

                //左侧上边距指示线
                var rect1 = {
                    x1: boundRect.left - len,
                    y1: boundRect.top,
                    x2: boundRect.left,
                    y2: boundRect.top
                };

                this.ctx.moveTo(rect1.x1, rect1.y1);
                this.ctx.lineTo(rect1.x2, rect1.y2);

                //左侧左边距指示线
                var rect2 = {
                    x2: boundRect.left,
                    y2: boundRect.top - len
                };

                this.ctx.lineTo(rect2.x2, rect2.y2);
                this.ctx.moveTo(rect1.x1, rect1.y1);

                this.ctx.closePath();
                this.ctx.stroke();

                this.ctx.beginPath();

                //右侧上边距指示线
                rect1 = {
                    x1: pageRect.width - boundRect.right + len,
                    y1: boundRect.top,
                    x2: pageRect.width - boundRect.right,
                    y2: boundRect.top
                };

                this.ctx.moveTo(rect1.x1, rect1.y1);
                this.ctx.lineTo(rect1.x2, rect1.y2);

                //右侧右边距指示线
                rect2 = {
                    x2: pageRect.width - boundRect.right,
                    y2: boundRect.top - len
                };

                this.ctx.lineTo(rect2.x2, rect2.y2);
                this.ctx.moveTo(rect1.x1, rect1.y1);

                this.ctx.closePath();
                this.ctx.stroke();

                //页脚部分
                var top = pageRect.height - boundRect.bottom;

                this.ctx.beginPath();

                //左侧上边距指示线
                rect1 = {
                    x1: boundRect.left - len,
                    y1: top,
                    x2: boundRect.left,
                    y2: top
                };

                this.ctx.moveTo(rect1.x1, rect1.y1);
                this.ctx.lineTo(rect1.x2, rect1.y2);

                //左侧左边距指示线
                rect2 = {
                    x2: boundRect.left,
                    y2: top + len
                };

                this.ctx.lineTo(rect2.x2, rect2.y2);
                this.ctx.moveTo(rect1.x1, rect1.y1);

                this.ctx.closePath();
                this.ctx.stroke();

                this.ctx.beginPath();

                //右侧上边距指示线
                rect1 = {
                    x1: pageRect.width - boundRect.right + len,
                    y1: top,
                    x2: pageRect.width - boundRect.right,
                    y2: top
                };

                this.ctx.moveTo(rect1.x1, rect1.y1);
                this.ctx.lineTo(rect1.x2, rect1.y2);

                //右侧右边距指示线
                rect2 = {
                    x2: pageRect.width - boundRect.right,
                    y2: top + len
                };

                this.ctx.lineTo(rect2.x2, rect2.y2);
                this.ctx.moveTo(rect1.x1, rect1.y1);

                this.ctx.closePath();
                this.ctx.stroke();

                if (opt.isHeadEditable) {
                    drawHeadFootLine.call(this, page);
                }

                if (setting && setting.pageBorderDisplay) {
                    this.drawPageBorder(page.getArea("body").getBoundRect(true));
                }

                if (setting.annotation.display) {
                    drawAnnotationsArea.call(this, opt.annotationProp);
                }
            }
        });
    }

    /**
     * 绘制页眉页脚标识线
     * @param {*} page 
     */
    var drawHeadFootLine = function (page) {
        this.ctx.strokeStyle = "#67C23A";
        this.ctx.lineDashOffset = 0;

        //页边距
        var padding = page.getPadding();
        //页面包围盒
        var boundRect = page.getBoundRect();

        //页眉实际高度
        var rect = page.getBoundRect("head");
        var top = rect.top + rect.height;
        
        top = top < padding.top 
            ? padding.top 
            : top;

        //页眉线
        this.ctx.setLineDash([3, 5]);
        this.ctx.beginPath();

        this.ctx.moveTo(0, top);
        this.ctx.lineTo(boundRect.width, top);

        this.ctx.closePath();
        this.ctx.stroke();

        //页面标签
        this.ctx.setLineDash([]);
        this.ctx.beginPath();

        this.ctx.moveTo(10, top);
        this.ctx.lineTo(10, top + 30);
        this.ctx.lineTo(60, top + 30);
        this.ctx.lineTo(60, top);

        this.ctx.closePath();
        this.ctx.stroke();

        this.ctx.fillStyle = "#eee";
        this.ctx.fillRect(10, top, 50, 30);

        this.ctx.fillStyle = "#444";
        this.ctx.font = "18px 宋体";
        this.ctx.fillText("页眉", 15, top + 20);

        //页脚线
        this.ctx.setLineDash([3, 5]);
        this.ctx.beginPath();
        this.ctx.strokeStyle = "#67C23A";

        rect = page.getBoundRect("foot");
        var top = boundRect.height - padding.bottom;
        
        top = rect.top > top
            ? top
            : rect.top;

        this.ctx.moveTo(0, top);
        this.ctx.lineTo(boundRect.width, top);

        this.ctx.closePath();
        this.ctx.stroke();

        //页脚标签
        this.ctx.setLineDash([]);
        this.ctx.beginPath();

        this.ctx.moveTo(10, top);
        this.ctx.lineTo(10, top - 30);
        this.ctx.lineTo(60, top - 30);
        this.ctx.lineTo(60, top);

        this.ctx.closePath();
        this.ctx.stroke();

        this.ctx.fillStyle = "#eee";
        this.ctx.fillRect(10, top - 30, 50, 30);

        this.ctx.fillStyle = "#444";
        this.ctx.font = "18px 宋体";
        this.ctx.fillText("页脚", 15, top - 10);

    }

    /**
     * 绘制批注区
     * @param {*} prop 
     */
    var drawAnnotationsArea = function (prop) {
        plm.createLayer(
            "background",
            ssDict.sPaintLayerLevel.ELEMENT_BACKGROUND,
            page.getIndex()
        ).push({
            name: "annotationAreaBackground",
            arguments: [prop.boundRect, {
                color: "#c6c6c6",
                width: 0.5
            }],
            method: (rect, style)=>{
                drawLine.call(this, style, (paint) => {
                    paint({
                        x1: rect.left,
                        y1: rect.top,
                        x2: rect.left,
                        y2: rect.top + rect.height
                    });
                },{ notAdjust: true });
            }
        });
    }

    /**
     * 绘制批注
     * @param {*} element 
     * @param {*} index 
     * @param {*} pageIndex 
     * @param {*} boundRect 
     * @param {*} opt
     */
    var drawAnnotation = function (element, index, pageIndex, boundRect, opt) {
        var prop = opt.annotationProp;

        var typeStyle = setting.annotation[element.annotation.type];
        typeStyle = typeStyle ? typeStyle : setting.annotation.info;

        var borderColor = element.annotation.focused 
            ? typeStyle.focus.borderColor
            : typeStyle.normal.borderColor;
        var backgroundColor = typeStyle.normal.backgroundColor;
        var elementBackcolor = element.annotation.focused 
            ? typeStyle.focus.borderColor
            : backgroundColor;

        //高亮显示元素
        plm.createLayer(
            "highlight",
            ssDict.sPaintLayerLevel.HIGHLIGHT,
            pageIndex,
            opt.zIndex ? opt.zIndex : null
        ).push({
            name: "annoEleBackground",
            arguments: [[boundRect], {backgroundColor: elementBackcolor}],
            method: this.fillByBoundRect
        });

        //元素最后一行显示批注内容
        if (element.__boundRect.length - 1 > pageIndex) return;
        if (element.__boundRect[pageIndex].length - 1 > index) return;

        //对批注内容排版
        if(element.annotationChildren && 
            element.annotationChildren.length > 0){

            //引导线起始位置
            var left = boundRect.left + boundRect.width;
            var top = boundRect.top + boundRect.height;

            //批注盒子高度
            var boxTop = top;

            if(prop.annotationBoxs && prop.annotationBoxs.length > 0){
                let lastBox = prop.annotationBoxs[prop.annotationBoxs.length - 1];
                boxTop = lastBox.boundRect.top + lastBox.boundRect.height + 5;
                boxTop = boxTop < top ? top : boxTop;
            }

            //第二条引导线的位置
            var line2Left = prop.pageRect.width - prop.pagePadding.right;

            //绘制引导线
            var lineRects = [
                {
                    x1: left,
                    y1: top,
                    x2: line2Left,
                    y2: top
                },
                {
                    x1: line2Left,
                    y1: top,
                    x2: prop.boundRect.left,
                    y2: boxTop + 20
                }
            ];

            //高亮显示引导线
            plm.createLayer(
                "highlight",
                ssDict.sPaintLayerLevel.HIGHLIGHT,
                pageIndex,
                opt.zIndex ? opt.zIndex : null
            ).push({
                name: "annoEleLine",
                arguments: [lineRects, {
                    color: borderColor,
                    width: 1
                }],
                method: (rects, style, opt)=>{
                    //上条线获得焦点，故本次不能覆盖
                    let notCover = opt.__lastFocused && 
                        opt.__lastRect && opt.__lastRect.y1 == rects[0].y1;
                    let operation = null;

                    if(notCover){
                        operation = this.ctx.globalCompositeOperation;
                        this.ctx.globalCompositeOperation = "destination-over";
                    }

                    drawLine.call(this, style, (paint) => {
                        for (var i in rects) {
                            paint(rects[i]);
                        }
                    },{ notAdjust: true });

                    if(operation){
                        this.ctx.globalCompositeOperation = operation;
                    }

                    if(!opt.__lastFocused){
                        opt.__lastRect = rects[0];
                        opt.__lastFocused = element.annotation.focused;
                    }
                }
            });

            //盒子包围盒
            var boxRect = {
                left: lineRects[1].x2,
                top: boxTop,
                width: prop.boundRect.width - 2,
                height: 0
            };

            //内容排版包围盒
            var rect = {
                left: boxRect.left,
                top: boxRect.top,
                width: boxRect.width,
                height: prop.boundRect.height
            }

            var innerPage = null;

            innerPage = innerFormatWithPaint.call(this, 
                {children: element.annotationChildren}, pageIndex, rect, {padding:"8,16"});

            boxRect.height = innerPage.getBoundRect("body").height + innerPage.getPadding().bottom + 5;

            //绘制盒子
            var style = { 
                borderWidth: 1,
                color: borderColor, 
                backgroundColor: backgroundColor 
            };
            
            plm.createLayer(
                "background",
                ssDict.sPaintLayerLevel.ELEMENT_BACKGROUND,
                pageIndex,
                opt.zIndex ? opt.zIndex : null
            ).push({
                name: "annotationBox",
                arguments: [boxRect, 0, style],
                method: roundRect
            });

            if(!prop.annotationBoxs){
                prop.annotationBoxs = [];
                page.setAnnotationBoxs(prop.annotationBoxs);
            }

            prop.annotationBoxs.push({
                annotation: element.annotation,
                boundRect: boxRect
            });
        }
    }

    /**
     * 绘制圆角矩形
     * @param {*} x 起始横坐标
     * @param {*} y 起始纵坐标
     * @param {*} width 宽度
     * @param {*} height 高度
     * @param {*} cornerRadius 弧度 
     * @param {*} style 样式
     */
    var roundRect = function (rect, cornerRadius, style) {
        if (style && style.borderWidth) {
            this.ctx.lineWidth = style.borderWidth;
        }

        let operation = this.ctx.globalCompositeOperation;
        this.ctx.globalCompositeOperation = "destination-over";

        // 开始路径并移动到矩形的左上角
        this.ctx.beginPath();
        this.ctx.moveTo(rect.left + cornerRadius, rect.top);

        var endX = rect.left + rect.width;
        var endY = rect.top + rect.height;

        // 绘制顶部边界线段
        this.ctx.lineTo(endX - cornerRadius, rect.top);

        // 添加右上角的弧线
        this.ctx.arcTo(endX, rect.top, endX, rect.top + cornerRadius, cornerRadius);

        // 绘制右侧边界线段
        this.ctx.lineTo(endX, endY - cornerRadius);

        // 添加右下角的弧线
        this.ctx.arcTo(endX, endY, endX - cornerRadius, endY, cornerRadius);

        // 绘制底部边界线段
        this.ctx.lineTo(rect.left + cornerRadius, endY);

        // 添加左下角的弧线
        this.ctx.arcTo(rect.left, endY, rect.left, endY - cornerRadius, cornerRadius);

        // 绘制左侧边界线段
        this.ctx.lineTo(rect.left, rect.top + cornerRadius);

        // 添加左上角的弧线
        this.ctx.arcTo(rect.left, rect.top, rect.left + cornerRadius, rect.top, cornerRadius);

        // 结束路径
        this.ctx.closePath();

        // 轮廓色
        this.ctx.strokeStyle = style && style.color ? style.color : "#000";
        // 描边矩形
        this.ctx.stroke();

        if (style && style.backgroundColor) {
            // 填充色
            this.ctx.fillStyle = style.backgroundColor;
            // 填充矩形
            this.ctx.fill();
        }

        this.ctx.globalCompositeOperation = operation;
    }

    /**
     * 优先获取可选项的序号
     * @param {*} pageIndex
     * @param {*} opt 
     * @returns 
     */
    var fetchPriority = function(pageIndex, opt){
        var zIndex = null;

        if(opt){
            if(opt.pageIndex){
                pageIndex = opt.pageIndex;
            }

            if(opt.zIndex){
                zIndex = opt.zIndex;
            }
        }

        return {
            pageIndex: pageIndex,
            zIndex: zIndex
        };
    }

    /**
     * 绘制文本
     * @param {*} text 
     * @param {*} index 行序号
     * @param {*} pageIndex 页序号
     * @param {*} opt 可选参数
     */
    this.drawText = function (text, index, pageIndex, opt) {
        if (text.style.display == "none") return;

        var boundRect = null;
        var textContent = null;

        if (opt.boundRect) {
            boundRect = opt.boundRect;
            textContent = text.__texts[pageIndex][index];
        } else {
            boundRect = text.__boundRect[pageIndex][index];
            textContent = text.__texts[pageIndex][index];
        }

        var left = boundRect.left;
        var top = boundRect.top;
        var width = boundRect.width;
        var charWidths = null;

        if (boundRect.paragraphOffsetWidth) {
            left += boundRect.paragraphOffsetWidth;
        }

        if (text.style) {
            if (text.style.letterSpacing) {
                if (!boundRect.letterSpacing) {
                    boundRect.letterSpacing = parseFloat(text.style.letterSpacing);
                } else {
                    //因为下面对文本宽度的计算没有将style的字符间隔算进去，故而此处加上
                    boundRect.letterSpacing += parseFloat(text.style.letterSpacing);
                }
            }
        }

        //字符间距
        if (boundRect.letterSpacing || opt.exportText) {
            this.ctx.fillStyle = text.style.color;
            this.ctx.font = text.getFontStyle(scale);

            var charWidth = 0;
            var charContent = "";

            charWidths = [];

            //Arial字体的数字1，两个1宽度不等于一个1宽度的两倍
            if (this.ctx.font.indexOf("Arial") > -1 && textContent.indexOf("11") > -1) {
                var nextContent = null;
                var lastContent = null;
                var oneWidth = this.measureCurText("11").width -
                    this.measureCurText("1").width;

                for (var i = 0; i < textContent.length; i++) {
                    charContent = textContent.substr(i, 1);
                    nextContent = textContent.substr(i + 1, 1);

                    metrics = this.measureCurText(charContent);

                    charWidths.push(charWidth);

                    if ((nextContent == "1" && charContent == "1") ||
                        (lastContent == "1" && charContent == "1")) {
                        charWidth += oneWidth;
                    } else {
                        charWidth += metrics.width;
                    }

                    lastContent = charContent;
                }
            } else {
                for (var i = 0; i < textContent.length; i++) {
                    charContent = textContent.substr(i, 1);
                    metrics = this.measureCurText(charContent);

                    charWidths.push(charWidth);
                    charWidth += metrics.width;
                }
            }

            var length = text.__hasNextVisibleText
                ? textContent.length
                : textContent.length > 0 ? textContent.length - 1 : 0;
            
            if(boundRect.letterSpacing != null){
                width = charWidth + boundRect.letterSpacing * length;
            }
        }

        //页码
        var priority = fetchPriority(pageIndex, opt);

        //背景色
        if (text.style.backgroundColor) {
            plm.createLayer(
                "background",
                ssDict.sPaintLayerLevel.ELEMENT_BACKGROUND,
                priority.pageIndex,
                priority.zIndex
            ).push({
                name: "textBackground",
                arguments: [[{
                    left: left,
                    top: boundRect.abovelineTop,
                    width: width,
                    height: boundRect.underlineTop - boundRect.abovelineTop
                }], text.style],
                method: (boundRects, style)=>{
                    if(!opt.exportTextBackground){
                        this.fillByBoundRect(boundRects, style);
                    }else{
                        opt.exportTextBackground(boundRects, {
                            style: style,
                            pageIndex: opt.pageIndex
                        });

                    }
                }
            });
        }

        //绘制文本内容
        plm.createLayer(
            "elementContent",
            ssDict.sPaintLayerLevel.ELEMENT_CONTENT,
            priority.pageIndex,
            priority.zIndex
        ).push({
            name: "textContent",
            arguments: [textContent, boundRect, left, top, charWidths, opt],
            method: (textContent, boundRect, left, top, charWidths, opt)=>{
                this.ctx.fillStyle = opt && opt.color ? opt.color : text.style.color;
                //背景文本
                if (text.innerText.length == 0 && text.placeholderColor) {
                    this.ctx.fillStyle = text.placeholderColor;
                }

                this.ctx.font = text.getFontStyle(scale);

                if(!opt.exportText){
                    //绘制文本内容
                    if (!boundRect.letterSpacing) {
                        this.ctx.fillText(textContent, boundRect.left, top);
                    } else {
                        for (var i = 0; i < textContent.length; i++) {
                            this.ctx.fillText(textContent.substr(i, 1), left +
                                charWidths[i] + boundRect.letterSpacing * i, top);
                        }
                    }
                }else{
                    let param = {
                        style: {
                            ...text.style, 
                            fontSize: (text.style.sub || text.style.sup)
                                ? text.style.fontSize / 2 
                                : text.style.fontSize
                        },
                        pageIndex: opt.pageIndex,
                        top: top - boundRect.textMetrics[FONT_ASCENT],
                        containENAndCN: opt.containENAndCN
                    };

                    if(opt.beforeExportText){
                        opt.beforeExportText(text, param);
                    }

                    let spacing = boundRect.letterSpacing
                        ? boundRect.letterSpacing
                        : 0;
                    //导出文本内容
                    for (var i = 0; i < textContent.length; i++) {
                        param.left = left + charWidths[i] + spacing * i;
                        opt.exportText(textContent.substr(i, 1), param);
                    }
                }
            }
        });

        //绘制双划线
        if (text.style.doubleDash) {
            plm.createLayer(
                "elementContent",
                ssDict.sPaintLayerLevel.ELEMENT_CONTENT,
                priority.pageIndex,
                priority.zIndex
            ).push({
                name: "doubleDash",
                arguments: [text, {
                    ...boundRect,
                    width: width,
                    left: left,
                    top: boundRect.top - boundRect.textMetrics[FONT_ASCENT]
                }],
                method: drawDoubleDash
            });
        }

        var lineStyle = { color: "#303133"};

        if (text.style.textDecoration) {
            //下划线
            if (text.style.textDecoration.indexOf("underline") > -1) {
                plm.createLayer(
                    "elementContent",
                    ssDict.sPaintLayerLevel.ELEMENT_CONTENT,
                    priority.pageIndex,
                    priority.zIndex
                ).push({
                    name: "underline",
                    arguments: [lineStyle, (paint) => {
                        paint({
                            x1: left,
                            y1: boundRect.underlineTop,
                            x2: left + width,
                            y2: boundRect.underlineTop
                        });
                    }],
                    method: (lineStyle, callback)=>{
                        if(!opt.exportTextDecoration){
                            drawLine.call(this, lineStyle, callback);
                        }else{
                            opt.exportTextDecoration(lineStyle, {
                                left: left,
                                top: boundRect.underlineTop,
                                width: width,
                                height: 1 * scale,
                                pageIndex: opt.pageIndex
                            });
                        }
                    }
                });
            }

            //删除线
            if (text.style.textDecoration.indexOf("line-through") > -1) {
                let y = top - boundRect.textMetrics[FONT_ASCENT] + boundRect.height / 2;

                plm.createLayer(
                    "elementContent",
                    ssDict.sPaintLayerLevel.ELEMENT_CONTENT,
                    priority.pageIndex,
                    priority.zIndex
                ).push({
                    name: "lineThrough",
                    arguments: [lineStyle, (paint) => {
                        paint({
                            x1: left,
                            y1: y,
                            x2: left + width,
                            y2: y
                        });
                    }],
                    method: (lineStyle, callback)=>{
                        if(!opt.exportTextDecoration){
                            drawLine.call(this, lineStyle, callback);
                        }else{
                            opt.exportTextDecoration(lineStyle, {
                                left: left,
                                top: y,
                                width: width,
                                height: 1 * scale,
                                pageIndex: pageIndex
                            });
                        }
                    }
                });
            }
        }

        if (text.innerText.length > 0 && opt && opt.elementBorderDisplay) {
            drawElementBorder.call(this, text, index, pageIndex, {
                ...boundRect,
                left: left
            }, width);
        }

        if (setting.emptyTextDisplay && (!textContent || textContent.length == 0)) {
            text.__fakeText = text.__fakeText ? text.__fakeText : "?";
            var metrics = this.measureCurText(text.__fakeText);
            var rect = {
                left: left + text.__fakeIndex * metrics.width,
                top: top - metrics[FONT_ASCENT],
                width: metrics.width + 2,
                height: metrics[FONT_ASCENT] + metrics[FONT_DESCENT]
            };

            drawRect.call(this, {
                backgroundColor: "black"
            }, rect);

            this.ctx.fillStyle = "#fff";
            this.ctx.fillText(text.__fakeText, rect.left, top);
        }

        if (text.annotation && setting.annotation.display) {
            drawAnnotation.call(this, text, index, priority.pageIndex, {
                left: left,
                top: boundRect.top - boundRect.textMetrics[FONT_ASCENT],
                width: width,
                height: boundRect.height
            }, opt);
        }

        if(opt.paragraph && opt.paragraph.titleType){
            this.ctx.fillStyle = "#000";
            let top = boundRect.top - boundRect.textMetrics[FONT_ASCENT];
            this.ctx.fillRect(boundRect.left - 10, top + (boundRect.height - 4) / 2, 4, 4);
        }
    }

    /**
     * 绘制双划线
     * @param {*} element 
     * @param {*} boundRect 
     */
    var drawDoubleDash = function (element, boundRect) {
        if (!setting.leaveTrace || !setting.traceDisplay) return;

        //双划线
        let lineStyle = {};

        let y1 = 0;
        let y2 = 0;

        if (element.style.doubleDash == "middle") {
            lineStyle.color = "red";
            y1 = boundRect.top + boundRect.height / 2;
            y2 = y1 + 4;
        } else if (element.style.doubleDash == "bottom") {
            lineStyle.color = "blue";
            y1 = boundRect.top + boundRect.height;
            y2 = y1 + 4;
        }

        drawLine.call(this, lineStyle, (paint) => {
            paint({
                x1: boundRect.left,
                y1: y1,
                x2: boundRect.left + boundRect.width,
                y2: y1
            });

            paint({
                x1: boundRect.left,
                y1: y2,
                x2: boundRect.left + boundRect.width,
                y2: y2
            });
        });
    }

    /**
     * 绘制元素界限框
     * @param {*} element 
     * @param {*} index 
     * @param {*} pageIndex 
     * @param {*} boundRect 
     * @param {*} width 
     */
    var drawElementBorder = function (element, index, pageIndex, boundRect, width) {
        this.ctx.lineWidth = 1.5;
        this.ctx.strokeStyle = "blue";

        var ascentTop = 0;
        var descentTop = 0;

        if (element._sType == "sText") {
            ascentTop = boundRect.textMetrics[boundRect.FONT_ASCENT];
            descentTop = boundRect.textMetrics[boundRect.FONT_DESCENT];
        } else {
            descentTop = boundRect.height;
        }

        if (!element.__boundRect[pageIndex][index - 1] &&
            !element.__boundRect[pageIndex - 1]) {

            this.ctx.beginPath();

            let rect1 = {
                x1: boundRect.left + 6,
                y1: boundRect.top - ascentTop,
                x2: boundRect.left,
                y2: boundRect.top - ascentTop + 2,
            };

            this.ctx.moveTo(rect1.x1, rect1.y1);
            this.ctx.lineTo(rect1.x2, rect1.y2);

            let rect2 = {
                x2: boundRect.left,
                y2: boundRect.top + descentTop - 2
            };

            this.ctx.lineTo(rect2.x2, rect2.y2);

            let rect3 = {
                x2: boundRect.left + 6,
                y2: boundRect.top + descentTop
            };

            this.ctx.lineTo(rect3.x2, rect3.y2);
            this.ctx.moveTo(rect1.x1, rect1.y1);

            this.ctx.closePath();
            this.ctx.stroke();
        }

        if (pageIndex == element.__boundRect.length - 1 &&
            index == element.__boundRect[pageIndex].length - 1) {

            this.ctx.beginPath();

            let rect1 = {
                x1: boundRect.left + width - 6,
                y1: boundRect.top - ascentTop,
                x2: boundRect.left + width,
                y2: boundRect.top - ascentTop + 2
            };

            this.ctx.moveTo(rect1.x1, rect1.y1);
            this.ctx.lineTo(rect1.x2, rect1.y2);

            let rect2 = {
                x2: boundRect.left + width,
                y2: boundRect.top + descentTop - 2
            };

            this.ctx.lineTo(rect2.x2, rect2.y2);

            let rect3 = {
                x2: boundRect.left + width - 6,
                y2: boundRect.top + descentTop
            };

            this.ctx.lineTo(rect3.x2, rect3.y2);
            this.ctx.moveTo(rect1.x1, rect1.y1);

            this.ctx.closePath();
            this.ctx.stroke();

            if (setting.paragraphIndexDisplay) {
                var text = "[" + element.__paragraphIndex + "]";

                this.ctx.fillStyle = "blue";
                this.ctx.font = "  18px Arial";
                var metrics = this.measureCurText(text);

                this.ctx.fillText(text,
                    boundRect.left + boundRect.width - metrics.width - 6,
                    boundRect.top - metrics[FONT_ASCENT] - metrics[FONT_DESCENT] + 4);
            }
        }

    }

    /**
     * 绘制段落标记
     * @param {*} paragraph 段落元素
     * @param {*} index 行号
     * @param {*} pageIndex 页码
     * @param {*} opt 可选参数
     */
    this.drawParagraph = function (paragraph, index, pageIndex, opt) {
        var boundRect = null;
        var priority = fetchPriority(pageIndex, opt);

        if (opt && opt.boundRect) {
            boundRect = opt.boundRect;
        } else {
            boundRect = paragraph.__boundRect[priority.pageIndex][index];
        }

        var r = scale / 2;
        var width = boundRect._width * r;
        var height = boundRect.height * r;
        var lineWidth = r < 1 ? 1 : r;

        var left = boundRect.left + width + 6 * r;
        var top = boundRect.top;

        if (boundRect.paragraphOffsetWidth) {
            left += boundRect.paragraphOffsetWidth;
        }

        if (setting.paragraphElementDisplay) {
            plm.createLayer(
                "elementContent",
                ssDict.sPaintLayerLevel.ELEMENT_CONTENT,
                priority.pageIndex,
                priority.zIndex
            ).push({
                name: "paragraphContent",
                arguments: [left, top, width, height],
                method: (left, top, width, height)=>{
                    this.ctx.strokeStyle = "#808080";
                    this.ctx.fillStyle = "#808080";
                    this.ctx.lineWidth = lineWidth;

                    this.ctx.beginPath();

                    this.ctx.moveTo(left, top);
                    this.ctx.lineTo(left, top + height);

                    this.ctx.moveTo(left, top + height);
                    this.ctx.lineTo(left - width, top + height);

                    this.ctx.moveTo(left - width, top + height / 2);
                    this.ctx.lineTo(left - width, top + height * 3 / 2);
                    this.ctx.lineTo(left - width * 5 / 3, top + height);
                    this.ctx.fill();

                    this.ctx.closePath();
                    this.ctx.stroke();
                }
            });
        }

        //绘制双划线
        if (paragraph.style.doubleDash) {
            plm.createLayer(
                "elementContent",
                ssDict.sPaintLayerLevel.ELEMENT_CONTENT,
                priority.pageIndex,
                priority.zIndex
            ).push({
                name: "doubleDash",
                arguments: [paragraph, { ...boundRect, top: boundRect.top }],
                method: drawDoubleDash
            });
        }

        if (setting.paragraphIndexDisplay) {
            this.ctx.fillStyle = "blue";
            this.ctx.font = "  18px Arial";

            var text = "[" + paragraph.__paragraphIndex + "]";
            var metrics = this.measureCurText(text);

            this.ctx.fillText(text, left + width + 5, top + height * 3 / 2);
            this.ctx.fillText("[" + JSON.stringify(paragraph.__relFor) + "]",
                left + width + metrics.width + 10, top + height * 3 / 2);
        }

    }

    /**
     * 绘制换行符
     * @param {*} paragraph 段落元素
     * @param {*} index 行号
     * @param {*} pageIndex 页码
     * @param {*} opt 可选参数
     */
    this.drawBreakline = function (breakline, index, pageIndex, opt) {
        var boundRect = null;
        var priority = fetchPriority(pageIndex, opt);

        if (opt && opt.boundRect) {
            boundRect = opt.boundRect;
        } else {
            boundRect = breakline.__boundRect[priority.pageIndex][index];
        }

        var left = boundRect.left + boundRect._width + 6;
        var top = boundRect.top;

        var height = boundRect.height;

        if (boundRect.paragraphOffsetWidth) {
            left += boundRect.paragraphOffsetWidth;
        }

        if (setting.paragraphElementDisplay) {
            plm.createLayer(
                "elementContent",
                ssDict.sPaintLayerLevel.ELEMENT_CONTENT,
                priority.pageIndex,
                priority.zIndex
            ).push({
                name: "breaklineContent",
                arguments: [left, top, height],
                method: (left, top, height)=>{
                    this.ctx.strokeStyle = "#808080";
                    this.ctx.fillStyle = "#808080";
                    this.ctx.lineWidth = 1;
        
                    this.ctx.beginPath();
        
                    this.ctx.moveTo(left, top);
                    this.ctx.lineTo(left, top + height);
        
                    this.ctx.moveTo(left - height / 2, top + height);
                    this.ctx.lineTo(left + height / 2, top + height);
                    this.ctx.lineTo(left, top + height * 3 / 2);
                    this.ctx.fill();
        
                    this.ctx.closePath();
                    this.ctx.stroke();
                }
            });
        }

        if (breakline.style.doubleDash) {
            plm.createLayer(
                "elementContent",
                ssDict.sPaintLayerLevel.ELEMENT_CONTENT,
                priority.pageIndex,
                priority.zIndex
            ).push({
                name: "doubleDash",
                arguments: [breakline, boundRect],
                method: drawDoubleDash
            });
        }
    }

    /**
     * 绘制层
     * @param {*} layer 层元素
     * @param {*} index 行号
     * @param {*} pageIndex 页码
     * @param {*} opt 可选参数
     */
    this.drawLayer = function (layer, index, pageIndex, opt) {
        if (layer.style.display == "none") return;

        var boundRect = null;
        var rect = null;
        var left = null;

        var priority = fetchPriority(pageIndex, opt);

        //绝对定位
        if(layer.style.position == "absolute"){
            opt = opt ? opt : {};
            boundRect = {
                left: layer.style.left,
                top: layer.style.top,
                width: layer.style.width,
                height: layer.style.height
            };

            left = boundRect.left;
            rect = boundRect;
        }else{
            boundRect = opt && opt.boundRect
                ? opt.boundRect
                : getElementBoundRect(layer, index, priority.pageIndex);

            left = boundRect.left;

            if (boundRect.paragraphOffsetWidth) {
                left += boundRect.paragraphOffsetWidth;
            }
    
            rect = {
                ...boundRect,
                left: left
            };
        }

        var presentType = layer.presentType;

        if (presentType == ssDict.sPresentType.LINE ||
            presentType == ssDict.sPresentType.PAGE_BREAK) {

            plm.createLayer(
                "elementContent",
                ssDict.sPaintLayerLevel.ELEMENT_CONTENT,
                priority.pageIndex,
                priority.zIndex
            ).push({
                name: "layerContent",
                arguments: [layer, rect],
                method: (layer, rect)=>{
                    let lineWidth = parseFloat(layer.style.lineWidth);
                    let ir = {
                        top: rect.top + (rect.height - lineWidth) / 2,
                        left: rect.left,
                        width: rect.width,
                        height: layer.style.lineWidth
                    };

                    this.ctx.lineWidth = lineWidth;
                    this.ctx.strokeStyle = opt.color 
                        ? opt.color 
                        : layer.style.color 
                            ? layer.style.color 
                            : "#606266";
        
                    if (layer.style.lineDash) {
                        this.ctx.lineDashOffset = 0;
                        this.ctx.setLineDash(layer.style.lineDash);
                    }
        
                    this.ctx.beginPath();
        
                    this.ctx.moveTo(ir.left, ir.top);
                    this.ctx.lineTo(ir.left + ir.width, ir.top);
        
                    this.ctx.closePath();
                    this.ctx.stroke();
        
                    if (layer.style.lineDash) {
                        this.ctx.setLineDash([]);
                    }
        
                    if (layer.children.length > 0) {
                        var child = null;
        
                        for (var i in layer.children) {
                            child = layer.children[i];
        
                            if (child._sType == "sText") {
                                this.ctx.color = child.style.color;
                                this.ctx.font = child.getFontStyle(scale);
        
                                let metrics = this.measureText(child);
        
                                let width = 10;
                                let height = metrics[FONT_ASCENT] + metrics[FONT_DESCENT];
                                let left = rect.left + (rect.width - metrics.width - width) / 2;
                                let top = rect.top + (rect.height - height) / 2;

                                if(ir.left > left){
                                    ir.left = left;
                                }

                                if(ir.top > top){
                                    ir.top = top;
                                }

                                if(ir.height < height){
                                    ir.height = height;
                                }
        
                                drawRect.call(this, { backgroundColor: "#fff" }, {
                                    left: left,
                                    top: top,
                                    width: metrics.width + width,
                                    height: height
                                });
        
                                left = rect.left + (rect.width - metrics.width) / 2;
        
                                this.ctx.fillStyle = child.style.color ? child.style.color : "#000";
                                this.ctx.fillText(child.innerText, left, top + metrics[FONT_ASCENT]);
                            }
                        }
                    }

                    if(opt.exportLayer){
                        let imageData = this.ctx.getImageData(ir.left, ir.top, ir.width, ir.height);
                        opt.exportLayer(layer, ir, {
                            imageData: imageData,
                            style: {...layer.style},
                            pageIndex: opt.pageIndex ? opt.pageIndex : pageIndex
                        })
                    }
                }
            });
        } else if (layer.children.length > 0) {
            var child = layer.children[0];

            if (child._sType == "sImage") {
                plm.createLayer(
                    "elementContent",
                    ssDict.sPaintLayerLevel.ELEMENT_CONTENT,
                    priority.pageIndex,
                    priority.zIndex
                ).push({
                    name: "image",
                    arguments: [layer.children[0], rect, opt],
                    method: (image, rect, opt)=>{
                        if(!opt.exportLayer){
                            drawImage.call(this, image, rect, opt);
                        }else{
                            opt.exportLayer(layer, rect, {
                                pageIndex: opt.pageIndex ? opt.pageIndex : pageIndex
                            });
                        }
                    }
                });
            } else {
                innerFormatWithPaint.call(this, layer, pageIndex, rect, opt);
            }
        }
        
        if (layer.style.textDecoration) {
            //下划线
            if(layer.style.textDecoration.indexOf("underline") > -1){
                plm.createLayer(
                    "elementContent",
                    ssDict.sPaintLayerLevel.ELEMENT_CONTENT,
                    priority.pageIndex,
                    priority.zIndex
                ).push({
                    name: "textDecoration",
                    arguments: [left, boundRect],
                    method: (left, boundRect)=>{
                        if(!opt.exportLayerDecoration){
                            drawLine.call(this, null, (paint) => {
                                paint({
                                    x1: left,
                                    y1: boundRect.underlineTop,
                                    x2: left + boundRect.width,
                                    y2: boundRect.underlineTop
                                });
                            });
                        }else{
                            opt.exportLayerDecoration(null, {
                                left: left,
                                top: boundRect.underlineTop,
                                width: boundRect.width,
                                height: 1 * scale,
                                pageIndex: opt.pageIndex ? opt.pageIndex : pageIndex
                            });
                        }
                    }
                });
            }

            //删除线
            if (layer.style.textDecoration.indexOf("line-through") > -1) {
                plm.createLayer(
                    "elementContent",
                    ssDict.sPaintLayerLevel.ELEMENT_CONTENT,
                    priority.pageIndex,
                    priority.zIndex
                ).push({
                    name: "textDecoration",
                    arguments: [left, boundRect],
                    method: (left, boundRect)=>{
                        let y = boundRect.top + boundRect.height / 2;

                        if(!opt.exportLayerDecoration){
                            drawLine.call(this, null, (paint) => {
                                paint({
                                    x1: left,
                                    y1: y,
                                    x2: left + boundRect.width,
                                    y2: y
                                });
                            });
                        }else{
                            opt.exportLayerDecoration(null, {
                                left: left,
                                top: y,
                                width: boundRect.width,
                                height: 1 * scale,
                                pageIndex: opt.pageIndex ? opt.pageIndex : pageIndex
                            });
                        }
                    }
                });
            }
        }

        //背景色
        if (layer.style.backgroundColor) {
            var width = boundRect.width;

            if (boundRect.letterSpacing) {
                width += boundRect.letterSpacing;
            }

            var rect2 = {
                left: left,
                top: boundRect.abovelineTop,
                width: width,
                height: boundRect.underlineTop - boundRect.abovelineTop
            };

            plm.createLayer(
                "background",
                ssDict.sPaintLayerLevel.ELEMENT_BACKGROUND,
                priority.pageIndex,
                priority.zIndex
            ).push({
                name: "layerBackground",
                arguments: [[rect2], layer.style],
                method: (boundRects, style)=>{
                    if(!opt.exportLayerBackground){
                        this.fillByBoundRect(boundRects, style);
                    }else{
                        opt.exportLayerBackground(boundRects, {
                            style: {...style},
                            pageIndex: opt.pageIndex ? opt.pageIndex : pageIndex
                        });
                    }
                }
            });
        }

        if (layer.style.doubleDash) {
            plm.createLayer(
                "background",
                ssDict.sPaintLayerLevel.ELEMENT_BACKGROUND,
                priority.pageIndex,
                priority.zIndex
            ).push({
                name: "doubleDash",
                arguments: [layer, boundRect],
                method: drawDoubleDash
            });
        }

        if (opt && opt.elementBorderDisplay) {
            drawElementBorder.call(this, layer, index, pageIndex, rect, rect.width);
        }
    }

    /**
     * 内部排版和渲染
     * @param {*} element 
     * @param {*} pageIndex 
     * @param {*} rect
     * @param {*} opt 
     */
    var innerFormatWithPaint = function(element, pageIndex, rect, opt){
        var pIndex = opt && opt.pageIndex 
            ? opt.pageIndex 
            : pageIndex;

        var pageRect = {
            left: 0,
            top: 0,
            width: rect.width,
            height: rect.height
        }

        var type = "body";
        var paragraphs = { body: [] };
        parseParagraph(element.children, 1, paragraphs.body);

        var pageOption = { paragraphs: paragraphs };
        if(opt && opt.padding){
            pageOption.style = {padding: opt.padding};
        }

        var innerPage = new sPage(pIndex, pageOption);
        var render = new sLayoutEngine(new sPainter(canvas), innerPage, scale, {
            pageRect: pageRect,
            setting: setting
        });

        var child = null;
        var parentRect = innerPage.getBoundRect("body", true);
        for (var i = 0; i < element.children.length; i++) {
            child = element.children[i];
            clearElementFormatProp(child);
            if (child._sType == "sText") {
                this.updateVariable(child, pIndex, opt);
                render.textFormat(child, parentRect, type, {
                    ignoreExceed: true
                });
            } else if (child._sType == "sParagraph") {
                render.paragraphFormat(child, parentRect, type);
            } else if (child._sType == "sCheckBox" || child._sType == "sRadio") {
                let margin = null;
                for (var j in child.children) {
                    clearElementFormatProp(child.children[j]);
                    if (child.children[j]._sType == "sText") {
                        render.textFormat(
                            child.children[j], parentRect, type, {
                            marginLeft: margin ? margin.right : null,
                            ignoreExceed: true
                        });
                    } else if (child.children[j]._sType == "sLayer") {
                        render.layerFormat(child.children[j], type);
                        margin = converter.parsePoM(child.children[j].style.margin);
                    }
                }
            } else if (child._sType == "sTable") {
                render.tableFormat(child, parentRect, type, { ignoreExceed: true });
            } else if(child._sType == "sLayer"){
                render.layerFormat(child, type);
            }
        }

        var exports = copyExportMethod(opt);

        innerPage.forEach((row, rowIndex, type) => {
            row.forEach((element) => {
                let option = {
                    pageIndex: pIndex,
                    ...exports
                };

                option.boundRect = this.translateElementRectTop(element,
                    rect.top + row.getBoundRect().top, rowIndex, option.pageIndex);
                option.boundRect.left += rect.left;

                switch (element._sType) {
                    case "sText":
                        this.drawText(element, rowIndex, innerPage.getIndex(), option);
                        break;
                    case "sLayer":
                        this.drawLayer(element, rowIndex, innerPage.getIndex(), option);
                        break;
                    case "sTable":
                        this.drawTable(element, rowIndex, innerPage.getIndex(), option);
                }
            }, {
                ignoreInvisible: true,
                containParagraph: true
            });
        });

        return innerPage;
    }

    /**
     * 复制导出方法
     * @param {*} opt 
     * @returns 
     */
    var copyExportMethod = function(opt){
        let exports = {};

        for(let i in opt){
            if(!/export/i.test(i)) continue;
            exports[i] = opt[i];
        }

        return exports;
    }

    /**
     * 解析段落
     * @param {*} elements 
     * @param {*} index 
     * @param {*} paragraphs 
     */
    var parseParagraph = function(elements, index, paragraphs){
        for(var i in elements){
            var element = elements[i];
            if(!element._sType) continue;

            element.__paragraphIndex = index;

            if(element._sType == "sParagraph"){
                paragraphs[index] = element;
                index++;
            }

            if(element.children && element._sType != "sLayer"){
                parseParagraph(element.children, ++index, paragraphs);
            }
        }
    }

    /**
     * 更新变量
     * @param {*} element 
     * @param {*} value
     * @param {*} opt
     * @returns 
     */
    this.updateVariable = function(element, value, opt){
        if(!element.variable) return;
        switch(element.variable.name){
            case "pageIndex":
                if(element.variable.format){
                    element.innerText = parseFormat(
                        element.variable.format, {
                        pageIndex: value,
                        pageSize: opt ? opt.pageSize : ""
                    });
                }
                break;
        }
    }

    /**
     * 页码格式化正则表达式
     */
    var formatRegxs = {
        "pageIndex": "\\{[\\s]*(pageIndex)[\\s]*[,]*[\\s]*(CN){0,1}[\\s]*\\}",
        "pageSize": "\\{[\\s]*(pageSize)[\\s]*[,]*[\\s]*(CN){0,1}[\\s]*\\}"
    };

    /**
     * 解析页码格式
     * @param {*} format 
     * @param {*} opt
     */
    var parseFormat = function(format, opt){
        for(let i in formatRegxs){
            let regex = new RegExp(formatRegxs[i], "gi");
            format = format.replace(regex, (match, index)=>{
                let arr = match.replace("{","").replace("}","").split(",");
                if(arr.length > 1 && arr[1].trim() == "CN"){
                    return converter.toChineseNumber(opt[i]);
                }else{
                    return opt[i];
                }
            });
        }
        return format;
    }

    /**
     * 清除元素的排版属性
     * @param {*} element 
     */
    var clearElementFormatProp = function (element) {
        delete element.__boundRect;
        delete element.__texts;
        delete element.__end;
        delete element.__attachElements;
    }

    /**
     * 绘制图层
     */
    this.drawPaintLayer = function (filter) {
        plm.forEach((shape, level, opt) => {
            if (filter && !filter(shape)) {
                return;
            }
            shape.arguments[shape.arguments.length] = opt;
            shape.method.call(this, ...shape.arguments);
        }, page.getIndex());
    }

    /**
     * 绘制输入域
     * @param {*} inputArea 输入域元素
     * @param {*} index 行号
     * @param {*} pageIndex 页码
     * @param {*} opt 可选参数
     */
    this.drawInputArea = function (inputArea, index, pageIndex, opt) {
        var priority = fetchPriority(pageIndex, opt);

        plm.createLayer(
            "elementContent",
            ssDict.sPaintLayerLevel.ELEMENT_CONTENT,
            priority.pageIndex,
            priority.zIndex
        ).push({
            name: "inputAreaContent",
            arguments: [inputArea, index, pageIndex, opt],
            method: drawInputArea
        });
    }

    /**
     * 绘制输入域
     * @param {*} table 表格元素
     * @param {*} index 行号
     * @param {*} pageIndex 页码
     * @param {*} opt 可选参数
     */
    var drawInputArea = function (inputArea, index, pageIndex, opt) {
        if (inputArea.style.display == "none") return;

        var boundRect = opt && opt.boundRect
            ? opt.boundRect
            : getElementBoundRect(inputArea, index, pageIndex);
        var left = boundRect.left;

        if (boundRect.paragraphOffsetWidth) {
            left += boundRect.paragraphOffsetWidth;
        }

        var rect = {
            ...boundRect,
            left: left
        };

        if (inputArea.tagView._sType == "sText") {
            var text = inputArea.tagView;

            if(!opt.exportInputArea){
                this.ctx.fillStyle = opt && opt.color ? opt.color : text.style.color;
                this.ctx.font = text.getFontStyle(scale);
    
                this.ctx.fillText(text.innerText, rect.left, rect.top);
            }else{
                rect.top -= rect.textMetrics[FONT_ASCENT];
                opt.exportInputArea(inputArea, {
                    left: rect.left,
                    top: rect.top,
                    style: {...text.style},
                    pageIndex: opt.pageIndex ? opt.pageIndex : pageIndex
                })
            }
        }
    }

    /**
     * 绘制表格
     * @param {*} table 表格元素
     * @param {*} index 行号
     * @param {*} pageIndex 页码
     * @param {*} opt 可选参数
     */
    this.drawTable = function(table, index, pageIndex, opt){
        var tRow = null;
        var cell = null;

        //表格位置
        var boundRect = opt && opt.boundRect
            ? opt.boundRect
            : {
                left: 0,
                top: 0
            };

        var range = getRowRange(table, index, pageIndex);

        var rowIndex = 0;
        var rowCount = range.length;
        var columnCount = table.getColumns().length;

        var spanCells = getSpanCells(table, index, pageIndex);

        //行绘制函数
        var drawRows = (range, pageIndex, isHead)=>{
            if(!range) return;
            for (let i = 0; i < range.length; i++) {
                rowIndex = range[i];
                tRow = table.getRows()[rowIndex];

                if(!tRow.__boundRect) return;
    
                for (let j = 0; j < tRow.getCells().length; j++) {
                    cell = tRow.getCells()[j];
    
                    if (cell.style.display == "none" || isSpanCell(cell)) continue;

                    let _opt = {
                        columnCount: columnCount,
                        rowCount: rowCount,
                        rowIndex: i,
                        colIndex: j,
                        ...opt
                    };

                    //为表头特殊设置(当表格起始页不在第一行的时候)
                    if(isHead){
                        _opt.pageIndex = pageIndex;
                        for(let m in cell.__boundRect){
                            if(isNaN(parseInt(m))) continue;
                            for(let n in cell.__boundRect[m]){
                                drawCell.call(this, cell, boundRect, n, m, _opt);
                            }
                        }
                    }else{
                        drawCell.call(this, cell, boundRect, index, pageIndex, _opt);
                    }
                }
    
                if (setting.tableRowBorderDisplay) {
                    drawTableRow.call(this, tRow, rowIndex, boundRect, index, pageIndex);
                }
            }
        }

        //绘制普通行
        drawRows(range, pageIndex);
        
        //绘制合并单元格
        for (let i = 0; i < spanCells.length; i++) {
            cell = spanCells[i];
            drawCell.call(this, cell.getRef(), boundRect, index, pageIndex, {
                columnCount: columnCount,
                rowCount: rowCount,
                rowIndex: cell.getRowIndex(),
                colIndex: cell.getColIndex(),
                ...opt
            });
        }

        //绘制表头行(非表格首页, 表格首页的表头是排版存在的行，这里是后续分页，只将表头重复绘制)
        var hearRows = getHeadRow(table, pageIndex);
        if(hearRows){
            drawRows(hearRows, pageIndex, true);
            //获取表头行的合并单元格
            let headSpanCells = getHeadSpanCell(table);
            let spanCell = null;

            for (let i = 0; i < headSpanCells.length; i++) {
                spanCell = headSpanCells[i];
                cell = spanCell.getRef();

                for(let m in cell.__boundRect){
                    if(isNaN(parseInt(m))) continue;
                    for(let n in cell.__boundRect[m]){
                        drawCell.call(this, cell, boundRect, n, m, {
                            columnCount: columnCount,
                            rowCount: rowCount,
                            rowIndex: spanCell.getRowIndex(),
                            colIndex: spanCell.getColIndex(),
                            ...opt,
                            pageIndex: pageIndex
                        });
                    }
                }
            }
        }

        if(opt.exportTable){
            opt.exportTable(table, boundRect, {
                type: opt.type,
                borderColor: opt.borderColor 
                    ? opt.borderColor 
                    : table.style && table.style.border
                        ? table.style.border.color 
                        : "#000",
                pageIndex: opt.pageIndex ? opt.pageIndex : pageIndex
            });
        }
    }

    /**
     * 获取表头
     * @param {*} table 
     * @param {*} pageIndex 
     */
    var getHeadRow = function(table, pageIndex){
        if(!table.__headRows || table.__headRows.length == 0) return;
        
        let row = null;
        let range = [];
        //只要当前页有实际排版的表头，则返回空
        for(let i = 0; i < table.__headRows.length; i++){
            row = table.getRows(table.__headRows[i]);
            
            if(row.__boundRect[pageIndex]){
                return null;
            }

            for(let j in row.__boundRect){
                if(range.indexOf(j) < 0){
                    range.push(j);
                }
            }
        }

        if(range.length > 1){
            return null;
        }

        return table.__headRows;
    }

    /**
     * 是否是合并单元格
     * @param {*} cell 
     */
    var isSpanCell = function(cell){
        return (cell.rowspan && cell.rowspan > 1) ||
                (cell.colspan && cell.colspan > 1); 
    }

    /**
     * 绘制表格行区域线
     * @param {*} row 
     * @param {*} tableRowIndex
     * @param {*} boundRect 
     * @param {*} index 
     * @param {*} pageIndex 
     */
    var drawTableRow = function (row, tableRowIndex, boundRect, index, pageIndex) {
        var rowRect = this.translateElementRectTop(row,
            boundRect.top, index, pageIndex);
        if (!rowRect) return false;

        var style = {
            color: "#eee",
            lineDash: [5, 3]
        };

        this.ctx.font = "20px Arial";
        this.ctx.fillText(tableRowIndex, rowRect.left + 10, rowRect.top + 30);

        drawLine.call(this, style, (paint) => {
            //下边
            paint({
                x1: 0,
                y1: rowRect.top + rowRect.height,
                x2: page.getBoundRect().width,
                y2: rowRect.top + rowRect.height
            })
        });
    }

    /**
     * 变换元素包围盒的上边距，不改变元素包围盒，只返回变换后的包围盒
     * @param {*} element 元素
     * @param {*} top 上边距
     * @param {*} index 行号
     * @param {*} pageIndex 页码
     * @returns 新的包围盒
     */
    this.translateElementRectTop = function(element, top, index, pageIndex){
        var boundRect = getElementBoundRect(element, index, pageIndex);

        if(!boundRect){
            return null;
        }

        return {
            ...boundRect,
            top: boundRect.top + top,
            underlineTop: boundRect.underlineTop + top,
            abovelineTop: boundRect.abovelineTop + top
        }
    }

    /**
     * 绘制单元格
     * @param {*} cell 单元格元素
     * @param {*} boundRect 表格包围盒
     * @param {*} index 页面行号
     * @param {*} pageIndex 页码
     * @param {*} opt 可选项
     * @returns 
     */
    var drawCell = function (cell, boundRect, index, pageIndex, opt) {
        var cellRect = this.translateElementRectTop(cell,
            boundRect.top, index, pageIndex);
        if (!cellRect) return false;

        cellRect.left += boundRect.left;

        var priority = fetchPriority(pageIndex, opt);

        if (opt) {
            plm.createLayer(
                "cellBorder",
                ssDict.sPaintLayerLevel.ELEMENT_CONTENT,
                priority.pageIndex,
                priority.zIndex
            ).push({
                name: "cellBorder",
                arguments: [cell, cellRect, opt],
                method: (cell, cellRect, opt)=>{
                    if(!opt.exportTable){
                        let rowCount = isSpanCell(cell) && 
                            (cell.rowspan + opt.rowIndex >= opt.rowCount)
                            ? opt.rowIndex + 1
                            : opt.rowCount;

                        let columnCount = isSpanCell(cell) && 
                            (cell.colspan + opt.colIndex >= opt.columnCount)
                            ? opt.colIndex + 1
                            : opt.columnCount;

                        //绘制单元格
                        drawCellBorder.call(this, 
                            cellRect, 
                            opt.rowIndex, 
                            opt.colIndex,
                            columnCount,
                            rowCount,
                            cell.style
                        );
                    }
                }
            });
        }

        if (!cell.__pageList) return false;

        //获取单元格当前内部分页
        var currentPage = cell.__pageList.getPage(pageIndex);

        if (!currentPage) return false;

        var top = 0;
        var exports = copyExportMethod(opt);
        var pIndex = opt.pageIndex ? opt.pageIndex : pageIndex;

        drawInRect.call(this, cellRect, () => {
            //绘制页边框
            if (setting && setting.pageBorderDisplay) {
                var pageRect = { ...currentPage.getBoundRect("body") };
                pageRect.left += cellRect.left;
                pageRect.top += cellRect.top;

                //加上垂直方向偏移量
                if (cell.__boundRect.verticalOffsetHeight) {
                    pageRect.top += cell.__boundRect.verticalOffsetHeight;
                }

                this.drawPageBorder(pageRect);
            }

            //绘制当前页文本
            currentPage.forEach((row, index, type) => {
                row.forEach((element) => {
                    let option = {
                        pageIndex: pIndex,
                        rangeRect: cellRect,
                        ...exports
                    };

                    top = 0;

                    //绘制行边框
                    if (setting && setting.rowBorderDisplay) {
                        var rowRect = { ...row.getBoundRect() };
                        rowRect.left += cellRect.left;
                        rowRect.top += cellRect.top;

                        //加上垂直方向偏移量
                        if (cell.__boundRect.verticalOffsetHeight) {
                            rowRect.top += cell.__boundRect.verticalOffsetHeight;
                        }

                        this.drawRowBorder(rowRect);
                    }

                    //加上表格、单元格、内部行左边距和上边距
                    if (element.__boundRect) {

                        //加上页面行上边距
                        top += row.getBoundRect().top;
                        //加上所在单元格上边距
                        top += cellRect.top;

                        //加上垂直方向偏移量
                        if (cell.__boundRect.verticalOffsetHeight) {
                            top += cell.__boundRect.verticalOffsetHeight;
                        }

                        option.boundRect = this.translateElementRectTop(element,
                            top, index, pageIndex);
                        if (!option.boundRect) return;

                        option.boundRect.left += cellRect.left;
                    }

                    copyColorStyle(option, opt);
                    option.elementBorderDisplay = opt.elementBorderDisplay;

                    switch (element._sType) {
                        case "sText":
                            this.drawText(element, index, pageIndex, option);
                            break;
                        case "sLayer":
                            this.drawLayer(element, index, pageIndex, option);
                            break;
                        case "sTable":
                            this.drawTable(element, index, pageIndex, option);
                            break;
                        case "sParagraph":
                            this.drawParagraph(element, index, pageIndex, option);
                            break;
                        case "sBreakline":
                            this.drawBreakline(element, index, pageIndex, option);
                            break;
                        case "sInputBegin":
                        case "sInputEnd":
                            this.drawInputArea(element, index, pageIndex, option);
                            break;
                    }
                }, {
                    ignoreInvisible: true,
                    containParagraph: true
                });
            })
        }, priority, opt)

        if(cell.gridLines){
            //绘制网格线
            plm.createLayer(
                "cellGrid",
                ssDict.sPaintLayerLevel.ELEMENT_CONTENT,
                priority.pageIndex,
                priority.zIndex
            ).push({
                name: "cellGrid",
                arguments: [cell, cellRect, opt],
                method: (cell, cellRect, opt)=>{
                    if(!opt.exportTable){
                        let voHeight = cell.__boundRect.verticalOffsetHeight;
                        let left = cellRect.left + 0.5;
                        let right = cellRect.left + cellRect.width - 0.5;
                        let minRowHeight = null;
                        let lastRowBottom = null;
                        
                        cell.__pageList.forEach((page, pageIndex)=>{
                            minRowHeight = null;
                            page.forEach((row, index, type)=>{
                                if(type != "body") return;

                                let rowRect = row.getBoundRect();
                                
                                lastRowBottom = voHeight + rowRect.top + rowRect.height;
                                let bottom = cellRect.top + lastRowBottom;

                                drawLine.call(this, null, (paint)=>{
                                    paint({
                                        x1: left,
                                        y1: bottom,
                                        x2: right,
                                        y2: bottom
                                    });
                                });

                                if(!minRowHeight || minRowHeight > rowRect.height){
                                    minRowHeight = rowRect.height;
                                }

                            });

                            let arr = [];

                            if(voHeight >= minRowHeight){
                                let topRowLen = Math.floor(voHeight / minRowHeight);
                                if(topRowLen > 0){
                                    for(let i = 0; i < topRowLen; i++){
                                        arr.push(cellRect.top + voHeight - minRowHeight * i);
                                    }
                                }
                            }

                            let minus = cellRect.height - lastRowBottom;

                            if(minus >= minRowHeight){
                                let bottomRowLen = Math.floor(minus / minRowHeight);
                                if(bottomRowLen > 0){
                                    for(let i = 1; i <= bottomRowLen; i++){
                                        arr.push(cellRect.top + lastRowBottom + minRowHeight * i);
                                    }
                                }
                            }

                            if(arr.length > 0){
                                let top = null;
                                for(let i in arr){
                                    top = arr[i];
                                    drawLine.call(this, null, (paint)=>{
                                        paint({
                                            x1: left,
                                            y1: top,
                                            x2: right,
                                            y2: top
                                        });
                                    });
                                }
                            }
                        });
                    }
                }
            });
        }

        return true;
    }

    /**
     * 颜色种类
     */
    var colorStyles = ["color", "backgroundColor", "borderColor"];

    /**
     * 复制样式
     * @param {*} option 
     * @param {*} opt 
     */
    var copyColorStyle = function(option, opt){
        if(!option || !opt) return;

        var c = null;

        for(var i in colorStyles){
            c = colorStyles[i];
            if(!opt[c]) continue;

            option[c] = opt[c];
        }
    }

    /**
     * 在限定的范围内渲染，超出范围不会显示
     * @param {*} rect 限定的包围盒
     * @param {*} callback 回调函数
     */
    var drawInRect = function(rect, callback, priority, opt){
        plm.createLayer(
            "cellClip",
            ssDict.sPaintLayerLevel.ELEMENT_CONTENT,
            priority.pageIndex,
            priority.zIndex
        ).push({
            name: "cellClip",
            arguments: [rect, opt],
            method: (rect, opt)=>{
                if(!opt.exportTable){
                    this.ctx.save();
        
                    this.ctx.beginPath();
                    
                    this.ctx.moveTo(rect.left, rect.top);
                    this.ctx.lineTo(rect.left + rect.width, rect.top);
                    this.ctx.lineTo(rect.left + rect.width, rect.top + rect.height - 1);
                    this.ctx.lineTo(rect.left, rect.top + rect.height - 1);
            
                    this.ctx.closePath();
            
                    this.ctx.clip();
                }
        
                callback();
            },
            afterMethodInvoke: (rect, opt)=>{
                if(!opt.exportTable) {
                    this.ctx.restore();
                }
            }
        });
    }

    /**
     * 获取有效的表格行序号范围
     * @param {*} table 表格元素
     * @param {*} index 页面行号
     * @param {*} pageIndex 页码
     * @returns 
     */
    var getRowRange = function(table, index, pageIndex){
        var rowCount = table.getRows().length;
        var range = [];
        var notFindCount = 0;
        var isFind = false;
        var boundRect = null;
        
        for(var i = 0; i < rowCount; i++){
            row = table.getRows()[i];

            if(!row.__boundRect) continue;

            boundRect = getElementBoundRect(row, index, pageIndex);
            if(!boundRect) {
                notFindCount++;

                if(notFindCount > 1 && isFind){
                    break;
                }

                continue;
            }else if(boundRect.height == 0){
                continue;
            }

            isFind = true;
            range.push(i);
        }

        return range;
    }

    /**
     * 是否可以绘制边框
     * @param {*} style 
     * @param {*} name
     */
    var canDrawBorder = function(style, name){
        if(style.border == "none"){
            return style[name] != "none" && style[name] != null;
        }else if(!style[name]){
            return style.border != "none" && style.border != null;
        }

        return style[name] != "none";
    }

    /**
     * 绘制单元格边框
     * @param {*} rect 单元格包围盒
     * @param {*} rowIndex 表格行号
     * @param {*} cellIndex 单元格序号
     * @param {*} columnCount 表格总列数
     * @param {*} rowCount 表格总行数
     * @param {*} style 可选项
     */
    var drawCellBorder = function(rect, rowIndex, cellIndex, columnCount, rowCount, style){
        let lineStyle = null;
        if(style.border != "none"){
            lineStyle = style.border;
        }

        drawLine.call(this, lineStyle, (paint)=>{
            if(canDrawBorder(style, "borderLeft")){
                //左边
                paint({
                    x1: rect.left + 0.5,
                    y1: rect.top - 1,
                    x2: rect.left + 0.5,
                    y2: rect.top + rect.height - 0.5
                }, style.borderLeft)
            }

            if(canDrawBorder(style, "borderTop")){
                //上边
                paint({
                    x1: rect.left + 0.5,
                    y1: rect.top + 0.5,
                    x2: rect.left + rect.width - 1,
                    y2: rect.top + 0.5
                }, style.borderTop)
            }
            
            if(cellIndex == columnCount - 1 && canDrawBorder(style, "borderRight")){
                //右边
                paint({
                    x1: rect.left + rect.width - 1,
                    y1: rect.top,
                    x2: rect.left + rect.width - 1,
                    y2: rect.top + rect.height - 0.5
                }, style.borderRight)
            }

            if(rowIndex == rowCount - 1 && canDrawBorder(style, "borderBottom")){
                //下边
                paint({
                    x1: rect.left + 0.5,
                    y1: rect.top + rect.height,
                    x2: rect.left + rect.width - 1,
                    y2: rect.top + rect.height
                }, style.borderBottom)
            }
        });
    }

    /**
     * 画线
     * @param {*} style 线的样式
     * @param {*} callback 回调函数
     * @param {*} opt 可选项
     */
    var drawLine = function(style, callback, opt) {
        this.ctx.lineWidth = 1;
		this.ctx.strokeStyle = "#606266";

        this.ctx.beginPath();

        callback((pos, subStyle)=>{
            setStyle.call(this, style);
            setStyle.call(this, subStyle);

            if(opt && opt.notAdjust){
                this.ctx.moveTo(pos.x1, pos.y1); 
                this.ctx.lineTo(pos.x2, pos.y2);  
                return;
            }

            if(pos.x1 == pos.x2){
                var x = [Math.floor(pos.x1) - 0.5, Math.floor(pos.x1)];

                for(var i in x){
                    this.ctx.moveTo(x[i], pos.y1); 
                    this.ctx.lineTo(x[i], pos.y2);  
                }
            }else if(pos.y1 == pos.y2){
                var y = [Math.floor(pos.y1) - 0.5, Math.floor(pos.y1)];

                for(var i in y){
                    this.ctx.moveTo(Math.floor(pos.x1) - 1, y[i]); 
                    this.ctx.lineTo(pos.x2, y[i]);  
                }
            }else{
                this.ctx.moveTo(pos.x1, pos.y1); 
                this.ctx.lineTo(pos.x2, pos.y2);  
            }
        }, this.ctx);

        this.ctx.closePath();
        this.ctx.stroke(); 

        if(style && style.lineDash){
            this.ctx.setLineDash([]);
        }
    }

    /**
     * 设置当前上下文样式
     * @param {*} style 
     */
    var setStyle = function(style){
        if(!style) return;

        this.ctx.lineWidth = style.width 
            ? style.width 
            : this.ctx.lineWidth;
        this.ctx.strokeStyle = style.color 
            ? style.color 
            : this.ctx.strokeStyle;

        if(style.lineDash){
            this.ctx.lineDashOffset = 0;
            this.ctx.setLineDash(style.lineDash);
        }
    }

    /**
     * 绘制矩形
     * @param {*} style 
     * @param {*} rect 
     */
    var drawRect = function(style, rect, opt) {
        this.ctx.fillStyle = opt && opt.backgroundColor ? opt.backgroundColor : style.backgroundColor;
        this.ctx.fillRect (rect.left, rect.top, rect.width, rect.height);
    }

    /**
     * 绘制图片
     * @param {*} image 图像对象
     * @param {*} rect 绘制范围
     * @param {*} opt 可选项
     */
    var drawImage = function(image, rect, opt){
        var filterColor = null;

        if(opt.imageFilterColor){
            filterColor = ()=>{
                this.ctx.fillStyle = opt.imageFilterColor;
                this.ctx.fillRect(rect.left, rect.top, rect.width, rect.height);
            };
        }

        if(!image.src || typeof(image.src) == "string"){
            image.addEventListener("load", ()=>{
                if(image.src){
                    paintForImage.call(this, image, rect, null, filterColor);
                }
            });
        }else{
            var gco = this.ctx.globalCompositeOperation;
            if(opt.globalCompositeOperation){
                this.ctx.globalCompositeOperation = opt.globalCompositeOperation;
                paintForImage.call(this, image, rect, filterColor, null);
            }else{
                paintForImage.call(this, image, rect, null, filterColor);
            }

            if(opt.globalCompositeOperation){
                this.ctx.globalCompositeOperation = gco;
            }
        }
    }

    /**
     * 绘制图像
     * @param {*} image 
     * @param {*} rect 
     */
    var paintForImage = function(image, rect, beforePaint, afterPaint){
        // if(opt && opt.rangeRect){
        //     drawInRect.call(this, opt.rangeRect, ()=>{
        //         if(beforePaint){ beforePaint() };
        //         this.ctx.drawImage(image.src, rect.left, rect.top, rect.width, rect.height);
        //         if(afterPaint){ afterPaint() };
        //     });
        // }else{
            if(beforePaint){ beforePaint() };
            this.ctx.drawImage(image.src, rect.left, rect.top, rect.width, rect.height);
            if(afterPaint){ afterPaint() };
        // }
    }

    /**
     * 获取合并单元格
     * @param {*} table 表格元素
     * @param {*} index 页面行序号
     * @param {*} pageIndex 页码
     * @returns 
     */
    var getSpanCells = function(table, index, pageIndex){
        if(!table.__spanCells) return null;

        var spanCell = null;
        var rect = null;
        var cells = [];

        for(var i = 0; i < table.__spanCells.length; i++){
            spanCell = table.__spanCells[i];
            rect = getElementBoundRect(spanCell.getRef(), index, pageIndex);
            if(!rect) continue;

            cells.push(spanCell);
        }

        return cells;
    }

    /**
     * 获取表头的合并单元格
     * @param {*} table 
     */
    var getHeadSpanCell = function(table){
        let spanCells = [];
        if(!table.__headRows || !table.__spanCells) return spanCells;

        for(let i in table.__spanCells){
            for(let j in table.__headRows){
                if(table.__spanCells[i].getRowIndex() == table.__headRows[j]){
                    spanCells.push(table.__spanCells[i]);
                    break;
                }
            }
        }

        return spanCells;
    }

    /**
     * 获取元素包围盒
     * @param {*} element 
     * @param {*} index 
     * @param {*} pageIndex 
     * @param {*} callback
     * @returns 
     */
    var getElementBoundRect = function(element, index, pageIndex, callback){
        var rect = null;

        if(index == -1){
            for(var i in element.__boundRect[pageIndex]){
                if(!element.__boundRect[pageIndex][i]) continue;
                rect = element.__boundRect[pageIndex][i];
                if(callback){
                    callback(rect, i);
                    return;
                }
            }
        }else if(index && element.__boundRect[pageIndex]){
            rect = element.__boundRect[pageIndex][index];
        }else{
            rect = element.__boundRect[pageIndex];    
        }
        
        if(callback){
            callback(rect);
        }else{
            return rect;
        }
    }

    /**
     * 绘制选择区域
     * @param {*} fragment 选择的片段
     */
    this.drawSelection = function (fragment) {
        if (!fragment) return;

        var member = null;
        var metrics = null;

        var font = this.ctx.font;

        var boundRects = [];
        var boundRect = null;
        var left = 0;
        var start = 0;
        var next = null;

        for (var i = 0; i < fragment.length; i++) {
            member = fragment[i];
            next = ost.extractOffset(member.offset, true);
            left = 0;

            // if((i == 0 || next.start == -1) && 
            //     next.start == next.end) continue;

            if (member.element._sType == "sText") {
                boundRect = member.boundRect;

                if (next.start != null) {

                    this.ctx.font = member.element.getFontStyle(scale);

                    start = next.start + 1;

                    left += this.measureCurText(member.text.substring(0, start), member.element).width;
                    if (boundRect.letterSpacing) {
                        left += boundRect.letterSpacing * start;
                    }

                    metrics = this.measureCurText(member.text.substr(start, next.end - next.start), member.element);

                    boundRect.left += left;
                    boundRect.width = metrics.width;

                    if (boundRect.letterSpacing) {
                        var len = member.isLast && next.end == member.text.length - 1 ? 1 : 0;
                        boundRect.width += boundRect.letterSpacing *
                            (next.end - next.start - len);
                    }
                }

                boundRects.push(boundRect);
            } else {
                boundRects.push(member.boundRect);
            }
        }

        plm.createLayer(
            "selection",
            ssDict.sPaintLayerLevel.SELECTION,
            page.getIndex()
        ).push({
            name: "selection",
            arguments: [boundRects],
            method: this.fillByBoundRect
        });

        // this.fillByBoundRect(boundRects);

        this.ctx.font = font;

        return boundRects;
    }

    /**
     * 绘制查找的区域
     * @param {*} fragment 片段
     */
    this.drawFindZone = function (fragment) {
        if (!fragment) return;

        var member = null;
        var metrics = null;

        var font = this.ctx.font;

        var boundRects = [];
        var boundRect = null;
        var left = 0;
        var start = 0;
        var next = null;

        var highlightRects = [];

        for (var i = 0; i < fragment.length; i++) {
            member = fragment[i];
            next = ost.extractOffset(member.offset, true);
            left = 0;

            if (member.element._sType == "sText") {
                boundRect = { ...member.boundRect };

                if (next.start != null) {

                    this.ctx.font = member.element.getFontStyle(scale);

                    start = next.start + 1;

                    left += this.measureCurText(member.text.substring(0, start), member.element).width;
                    if (boundRect.letterSpacing) {
                        left += boundRect.letterSpacing * start;
                    }

                    metrics = this.measureCurText(member.text.substr(start, next.end - next.start), member.element);

                    boundRect.left += left;
                    boundRect.width = metrics.width;

                    if (boundRect.letterSpacing) {
                        var len = member.isLast && next.end == member.text.length - 1 ? 1 : 0;
                        boundRect.width += boundRect.letterSpacing *
                            (next.end - next.start - len);
                    }
                }

                boundRects.push(boundRect);
            } else if (member.element._sType == "sTableCell") {
                boundRects.push(member.boundRect);
            } else {
                if (next.start == -1 && next.end == -1) continue;

                if (member.element._sType == "sLayer") {
                    boundRects.push(member.boundRect);
                } else if (member.element._sType == "sParagraph") {
                    boundRects.push(member.boundRect);
                } else if (member.element._sType == "sBreakline") {
                    boundRects.push(member.boundRect);
                }
            }

            //高亮显示该查找区域
            if(member.highlight){
                highlightRects.push(boundRect);
            }
        }

        plm.createLayer(
            "findZone",
            ssDict.sPaintLayerLevel.FIND_ZONE,
            page.getIndex()
        ).push({
            name: "findZone",
            arguments: [boundRects, { backgroundColor: "#e9f405c4" }],
            method: this.fillByBoundRect
        });

        //高亮显示某个特定查找区域
        if(highlightRects.length > 0){
            plm.createLayer(
                "findZoneHighlight",
                ssDict.sPaintLayerLevel.HIGHLIGHT,
                page.getIndex()
            ).push({
                name: "findZoneHighlight",
                arguments: [highlightRects, { backgroundColor: "#b7bf12" }],
                method: this.fillByBoundRect
            });
        }

        this.ctx.font = font;

        return boundRects;
    }

    /**
     * 绘制差异行
     * @param {*} row 
     * @param {*} opt 
     */
    this.drawDiffRow = function (row, opt) {
        opt = opt ? opt : {};

        if (opt.diffRects) {
            plm.createLayer(
                "highlight",
                ssDict.sPaintLayerLevel.HIGHLIGHT,
                row.getPage().getIndex()
            ).push({
                name: "diffHighlight",
                arguments: [opt.diffRects, { backgroundColor: "yellow" }],
                method: this.fillByBoundRect
            });
        }

        if (opt.backDisplay) {
            plm.createLayer(
                "background",
                ssDict.sPaintLayerLevel.ELEMENT_BACKGROUND,
                row.getPage().getIndex()
            ).push({
                name: "rowBackground",
                arguments: [[row.getBoundRect()], { backgroundColor: "#f2bbbb" }],
                method: this.fillByBoundRect
            });
        }

        if (opt.plus || opt.minus) {
            var rect = row.getBoundRect();
            var boxWidth = 32;
            var lineWidth = 16;
            var lineThickness = 0.5;

            drawLine.call(this, { width: lineThickness, color: "#000" }, (paint) => {
                let x1 = rect.left - boxWidth + (boxWidth - lineWidth) / 2;
                let y1 = rect.top + (rect.height - lineThickness) / 2;

                paint({
                    x1: x1,
                    y1: y1,
                    x2: x1 + lineWidth,
                    y2: y1
                });

                if (opt.plus) {
                    x1 = rect.left - (boxWidth - lineThickness) / 2;
                    y1 = rect.top + (rect.height - lineWidth) / 2;

                    paint({
                        x1: x1,
                        y1: y1,
                        x2: x1,
                        y2: y1 + lineWidth
                    });
                }
            }, { notAdjust: true });
        }
    }

    /**
     * 绘制行号
     * @param {*} row 
     */
    this.drawRowNumber = function (row, number) {
        var rect = row.getBoundRect();

        this.ctx.fillStyle = "#aaa";
        this.ctx.font = "22px Arial";

        number = number ? number : row.getIndex();
        textMetrics = this.measureCurText(number);

        this.ctx.fillText(number, rect.left - textMetrics.width - 10,
            rect.top + textMetrics[FONT_ASCENT] +
            (rect.height - textMetrics[FONT_ASCENT] - textMetrics[FONT_DESCENT]) / 2);
    }

    /**
     * 绘制分页边框
     * @param {*} rect 
     */
    this.drawPageBorder = function (rect) {
        this.ctx.strokeStyle = "#409EFF";
        this.ctx.setLineDash([5, 3]);
        this.ctx.strokeRect(rect.left, rect.top, rect.width - 2, rect.height);
        this.ctx.setLineDash([]);
    }

    /**
     * 绘制页内行边框
     * @param {*} rect
     */
    this.drawRowBorder = function (rect) {
        this.ctx.strokeStyle = "gray";
        this.ctx.setLineDash([5, 3]);
        this.ctx.strokeRect(rect.left + 1, rect.top + 1, rect.width - 2, rect.height - 2);
        this.ctx.setLineDash([]);

        var text = "top: " + rect.top;
        var metrics = this.measureCurText(text);
        var height = metrics[FONT_ASCENT] + metrics[FONT_DESCENT];

        this.ctx.fillText(text,
            rect.left + rect.width + 10, rect.top + (rect.height - height) / 2 + metrics[FONT_ASCENT]);
    }

    /**
     * 绘制水印
     * @param {*} watermark 
     * @param {*} rect 
     * @param {*} pageIndex
     * @param {*} option
     */
    this.drawWatermark = function(watermark, rect, pageIndex, option) {
        if(!watermark || watermark.content == null || watermark.content.length == 0) return;
        
        if(setting.annotation.display && option.annotationWidth){
            rect.width -= option.annotationWidth;
        }

        plm.createLayer(
            "watermark",
            ssDict.sPaintLayerLevel.CONTEXT_BACKGROUND,
            pageIndex,
            0
        ).push({
            name: "watermark",
            arguments: [watermark, rect],
            method: (watermark, rect)=>{
                let rowLen = watermark.rowcount ? watermark.rowcount : 1;
                let colLen = watermark.colcount ? watermark.colcount : 1;
                let rotate = watermark.style.rotate ? watermark.style.rotate : 0;

                let metrics = this.measureCurText(watermark.content);
            
                let textWidth = metrics.width;
                let textHeight = metrics[FONT_ASCENT] + metrics[FONT_DESCENT];
                let unitWidth = rect.width / colLen;
                let unitHeight = rect.height / rowLen;

                let translateOffsets = [];
                let waterRect = {
                    left: 0,
                    top: textHeight / 2
                };

                for(let i = 0; i < rowLen; i++){
                    for(let j = 0; j < colLen; j++){
                        translateOffsets.push({
                            left: unitWidth * j + (unitWidth - textWidth) / 2,
                            top: unitHeight * i + (unitHeight - textHeight) / 2
                        });
                    }
                }

                if(!option.exportWatermark){
                    //保存初始状态
                    this.ctx.save();
    
                    this.ctx.font = getFontStyle(watermark.style, scale);
                    this.ctx.fillStyle = watermark.style.color;
            
                    let offset = null;
                    for(let i in translateOffsets){
                        offset = translateOffsets[i];

                        //以下两个操作各自都有叠加效果，所以必须逐个反向操作一次
                        this.ctx.translate(offset.left, offset.top);
                        this.ctx.rotate(Math.PI / 180 * rotate);

                        this.ctx.fillText(watermark.content, 0, textHeight / 2);

                        //反向操作必须和正向操作的步骤相反
                        this.ctx.rotate(-Math.PI / 180 * rotate);
                        this.ctx.translate(-offset.left, -offset.top);
                    }

                    //恢复初始状态
                    this.ctx.restore();
                }else{
                    option.exportWatermark(
                        watermark.content, 
                        waterRect, {
                            rotate: rotate,
                            rowcount: rowLen,
                            colcount: colLen,
                            style: {...watermark.style},
                            translateOffsets: translateOffsets,
                            pageIndex: option.pageIndex 
                                ? option.pageIndex 
                                : pageIndex
                        }
                    );
                }
            }
        });
    }

    /**
     * 绘制底纹
     * @param {*} texture 
     * @param {*} rect 
     * @param {*} pageIndex 
     * @param {*} option
     */
    this.drawTexture = function(texture, rect, pageIndex, option){
        if(!texture || (!texture.style.backgroundColor && !texture.image)) return;

        if(setting.annotation.display && option.annotationWidth){
            rect.width -= option.annotationWidth;
        }

        plm.createLayer(
            "texture",
            ssDict.sPaintLayerLevel.CONTEXT_BACKGROUND_IMAGE,
            pageIndex,
            0
        ).push({
            name: "texture",
            arguments: [texture, rect],
            method: (texture, rect)=>{
                if(!option.exportTexture){
                    if(texture.image){
                        this.ctx.drawImage(texture.image, rect.left, rect.top, rect.width, rect.height);
                    }else if(texture.style.backgroundColor){
                        this.ctx.fillStyle = texture.style.backgroundColor;
                        this.ctx.fillRect(rect.left, rect.top, rect.width, rect.height);
                    }
                }else{
                    option.exportTexture(texture, rect, {
                        pageIndex: option.pageIndex ? option.pageIndex : pageIndex
                    });
                }
            }
        });
    }

    /**
     * 获取字体样式
     * @param {*} ratio 
     * @param {*} opt 
     * @returns 
     */
    var getFontStyle = function (style, ratio, opt) {
        var fStyle = "";

        if(style.fontStyle){
            fStyle += style.fontStyle + " ";
        }

        if (style.fontWeight) {
            fStyle += style.fontWeight + " ";
        }

        if (style.fontSize) {
            fStyle += (parseFloat(style.fontSize) * 
                parseFloat(ratio ? ratio : 1)).toFixed(4) + "px ";
        }

        if(opt && opt.fontFamily){
            fStyle += opt.fontFamily + " ";
        }else if (style.fontFamily) {
            fStyle += style.fontFamily + " ";
        }

        return fStyle;
    }

    /**
     * 测量文本
     * @param {*} element 文本元素
     * @param {*} text 文本内容 可选
     * @returns 
     */
    this.measureText = function (element, text, opt) {
        var font = this.ctx.font;

        this.ctx.font = element.getFontStyle(scale);

        var metrics = this.measureCurText(
            text != null
                ? text
                : element.innerText,
            element,
            opt
        );

        this.ctx.font = font;

        return metrics;
    }

    /**
     * 测量当下环境文本属性
     * @param {*} text 文本内容
     * @param {*} element 文本元素
     * @param {*} opt
     * @returns 
     */
    this.measureCurText = function (text, element, opt) {
        let metrics = this.ctx.measureText(text);

        if (element) {
            if (element.style && element.style.letterSpacing) {
                metrics = createTextMetrics(metrics);
                metrics.width += text.length * parseFloat(element.style.letterSpacing);
            } else if (opt && opt.new) {
                metrics = createTextMetrics(metrics);
            }
        } else if (opt && opt.new) {
            metrics = createTextMetrics(metrics);
        }

        return metrics;
    }

    /**
     * 创建一个文本度量对象
     * @param {*} metrics 
     * @returns 
     */
    var createTextMetrics = function (metrics) {
        var textMetrics = {};

        textMetrics["FONT_ASCENT"] = FONT_ASCENT;
        textMetrics["FONT_DESCENT"] = FONT_DESCENT;
        textMetrics[FONT_ASCENT] = metrics[FONT_ASCENT];
        textMetrics[FONT_DESCENT] = metrics[FONT_DESCENT];
        textMetrics.width = metrics.width;

        return textMetrics;
    }

    /**
     * 根据包围盒做矩形填充
     * @param {*} boundRects 包围盒数组
     * @param {*} style 可选 {backgroundColor: ""}
     */
    this.fillByBoundRect = function (boundRects, style) {
        if(style){
            if(!style.backgroundColor){
                style.backgroundColor = "#409eff6e";
            }
        }else{
            style = { backgroundColor: "#409eff6e" };
        }

        // let operation = this.ctx.globalCompositeOperation;
        // this.ctx.globalCompositeOperation = "destination-over";

        for (var j = 0; j < boundRects.length; j++) {
            drawRect.call(this, style, boundRects[j]);
        }

        // this.ctx.globalCompositeOperation = operation;
    }

    /**
     * 绘制矩形
     * @param {*} style 
     * @param {*} rect 
     */
    var drawRect = function(style, rect, opt) {
        this.ctx.fillStyle = opt && opt.backgroundColor ? opt.backgroundColor : style.backgroundColor;
        this.ctx.fillRect (rect.left, rect.top, rect.width, rect.height);
    }

    /**
     * 清除选择区域
     */
    this.clearSelection = function () {
        plm.clear(ssDict.sPaintLayerLevel.SELECTION, page.getIndex());
    }

    /**
     * 清除查找区域
     */
    this.clearFindZone = function () {
        plm.clear(ssDict.sPaintLayerLevel.FIND_ZONE, page.getIndex());
    }

    /**
     * 清除画面
     */
    this.clear = function (rect) {
        var boundRect = rect ? rect : page.getBoundRect();
        this.ctx.clearRect(0, 0, boundRect.width, boundRect.height);
    }
}